#
# \brief  Dependency-resolution functions
# \author Norman Feske
# \date   2017-03-22
#
# The following accessor functions must be defined when including this file:
#
#   api_file          return path to 'api' file of a library source archive
#   used_apis_file    return path to 'used_apis' file for a source archive
#   pkg_src_archives  return source archives of a package
#   pkg_raw_archives  return raw-data archives of a package
#   pkg_pkg_archives  return package-archive dependencies of a package
#

#
# Extend ARCHIVES(pkg) with package dependencies
#

_pkg_archives = $(call pkg_pkg_archives,$1)

_check_unvisited = $(if $(filter $(VISITED_PKGS),$1),\
                      $(error recursive package dependency: $(VISITED_PKGS)),\
                      $(eval VISITED_PKGS += $1))

_pkg_deps_rec = $(call _check_unvisited,$1) $1 \
                   $(foreach PKG,$(call _pkg_archives,$1),\
                      $(call _pkg_deps_rec,$(PKG)))

_pkg_deps = $(foreach PKG,$1,\
               $(eval VISITED_PKGS :=) $(call _pkg_deps_rec,$(PKG)))

ARCHIVES(pkg) := $(sort ${ARCHIVES(pkg)} $(call _pkg_deps,${ARCHIVES(pkg)}))


#
# Extend ARCHIVES(binpkg) with binary-package dependencies
#

# return list of source archives needed by a given binary package
_binpkg_src_archives = $(call pkg_src_archives,$(call pkg_of_binpkg,$1))

# return list of package archives contained in a binary package
_binpkg_pkg_archives = $(foreach P,$(call pkg_pkg_archives,$(call pkg_of_binpkg,$1)),\
                          $(call binpkg_for_pkg,$(call bin_archive_spec,$1),$P))

# override behavior of '_pkg_archives' to work on binary packages
_pkg_archives = $(call _binpkg_pkg_archives,$1)

ARCHIVES(binpkg) := $(sort ${ARCHIVES(binpkg)} $(call _pkg_deps,${ARCHIVES(binpkg)}))


#
# Extend ARCHIVES(pkg) with binary-package dependencies
#

ARCHIVES(pkg) := $(sort ${ARCHIVES(pkg)} $(foreach P,${ARCHIVES(binpkg)},\
                                            $(call pkg_of_binpkg,$P)))

#
# Extend ARCHIVES(bin) with binary-package dependencies
#

# return non-empty result if source archive exists
_src_exists = $(wildcard $(dir $(call used_apis_file,$1)))

# return binary-archive path for architecture $1 and source archive $2
_bin_for_src = $(strip \
                  $(if $(call _src_exists,$2),\
                     $(call archive_user,$2)/bin/$1/$(call archive_recipe,$2)/$(call archive_version,$2)))

# return list of binary archives contained in a binary package
_binpkg_bin_archives = $(foreach S,$(call _binpkg_src_archives,$1),\
                          $(call _bin_for_src,$(call bin_archive_spec,$1),$S))


ARCHIVES(bin) := $(sort ${ARCHIVES(bin)} $(foreach P,${ARCHIVES(binpkg)},\
                                            $(call _binpkg_bin_archives,$P)))

#
# Populate ARCHIVES(dbg) with debug-packages
#

ifneq ($(DBG),)
_dbg_from_bin = $(call archive_user,$1)/dbg/$(call bin_archive_spec,$1)/$(call bin_archive_recipe,$1)/$(call bin_archive_version,$1)
ARCHIVES(dbg) := $(foreach A,${ARCHIVES(bin)},$(call _dbg_from_bin,$A))
endif

#
# Extend ARCHIVES(src) with package dependencies
#

ARCHIVES(src) := $(sort ${ARCHIVES(src)} $(foreach P,${ARCHIVES(pkg)},\
                                            $(call pkg_src_archives,$P)))

#
# Extend ARCHIVES(raw) with package dependencies
#

ARCHIVES(raw) := $(sort ${ARCHIVES(raw)} $(foreach P,${ARCHIVES(pkg)},\
                                            $(call pkg_raw_archives,$P)))

#
# Extend ARCHIVES(src) with binary dependencies
#

ARCHIVES(src) := $(sort ${ARCHIVES(src)}\
                    $(foreach B,${ARCHIVES(bin)},\
                       $(call src_of_bin,$B)))

#
# Extend ARCHIVES(api) with the APIs used by ARCHIVES(src)
#
# The 'used_apis' file can contain fully specified entries or shortcuts.
# A fully specified entry has the form '<user>/api/<name>/version'.
# A shortcut has the form '<name>/version'. In this case, the '<user>' is
# implicitely equal to the depot user of the src archive.
#
_used_apis = $(call file_content,$(call used_apis_file,$1))

api_full_specified = $(call path_element,4,$1)

src_api_archives = $(foreach A,$(call _used_apis,$1),\
                      $(if $(call api_full_specified,$A),\
                         $A,$(addprefix $(call archive_user,$1)/api/,$A)))

ARCHIVES(api) := $(sort ${ARCHIVES(api)} $(foreach A,${ARCHIVES(src)},\
                                            $(call src_api_archives,$A)))

#
# Extend ARCHIVES(api) with the APIs implemented by library ARCHIVES(src)
#

_lib_api = $(call file_content,$(call api_file,$1))

_lib_api_archive = $(addprefix $(call archive_user,$1)/api/,$(call _lib_api,$1))

ARCHIVES(api) := $(sort ${ARCHIVES(api)} $(foreach A,${ARCHIVES(src)},\
                                            $(call _lib_api_archive,$A)))
